package chapter.c5d14;

import java.lang.reflect.*;
import java.util.Scanner;

public class ReflectionTest {
    public static void main(String[] args) throws ClassNotFoundException {
        String name;
        if (args.length == 0) {
            System.out.println("Enter class name(e.g. java.util.Date):");
            Scanner in = new Scanner(System.in);
            name = in.next();
        } else {
            name = args[0];
        }

        Class clz = Class.forName(name);
        Class superClz = clz.getSuperclass();

        String modifiers = Modifier.toString(clz.getModifiers());
        if (modifiers.length() > 0) System.out.print(modifiers + " ");
        System.out.print("class " + name);

        if (superClz != null && superClz != Object.class) System.out.print(" extends " + superClz.getName());

        System.out.print(" {\n");
        printConstructors(clz);
        System.out.println();
        System.out.println();

        printMethods(clz);
        System.out.println();
        System.out.println();

        printFields(clz);
        System.out.print("\n}\n");
    }

    public static void printConstructors(Class clz) {
        Constructor[] constructors = clz.getDeclaredConstructors();

        for (Constructor constructor : constructors) {
            String name = constructor.getName();
            System.out.print("    ");
            String modifiers = Modifier.toString(clz.getModifiers());

            if (modifiers.length() > 0) System.out.print(modifiers + " ");
            System.out.print(name + "(");

            Class[] paramTypes = constructor.getParameterTypes();
            for (int i = 0; i < paramTypes.length; i++) {
                if (i > 0) System.out.print(", ");
                System.out.print(paramTypes[i].getName());
            }

            System.out.print(");");
            System.out.println();
        }
    }

    public static void printMethods(Class clz) {
        Method[] methods = clz.getMethods();

        for (Method method : methods) {
            System.out.print("    ");

            Class retType = method.getReturnType();
            String name = method.getName();
            String modifiers = Modifier.toString(method.getModifiers());
            if (modifiers.length() > 0) System.out.print(modifiers + " ");

            System.out.print(retType.getName() + " " + name + "(");

            Class[] paramsTypes = method.getParameterTypes();
            for (int i = 0; i < paramsTypes.length; i++) {
                if (i > 0) System.out.print(", ");
                System.out.print(paramsTypes[i].getName());
            }

            System.out.println(");");
        }
    }

    public static void printFields(Class clz) {
        Field[] fields = clz.getFields();

        for (Field field: fields) {
            System.out.print("    ");

            String name = field.getName();
            Class type = field.getType();
            String modifiers = Modifier.toString(field.getModifiers());

            if (modifiers.length() > 0) System.out.print(modifiers + " ");
            System.out.println(type.getName() + " " + name + ";");
        }
    }
}
